/*
 * Preferences.java
 *
 * Created on November 6, 2008, 8:08 AM
 */

package com.leadiv.openrule;

import com.centerkey.utils.BareBonesBrowserLaunch;
import java.awt.Color;
import java.awt.Toolkit;
import java.util.Hashtable;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.prefs.BackingStoreException;
import java.util.prefs.PreferenceChangeListener;
import javax.swing.DefaultComboBoxModel;
import javax.swing.ImageIcon;
import javax.swing.JColorChooser;
import javax.swing.JOptionPane;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;

/**
 *
 * @author  pborrego
 */
public class Preferences extends javax.swing.JFrame implements DocumentListener {

    /** Creates new form Preferences */
    public Preferences(PreferenceChangeListener notify) {
        this.defaultPrefs(notify);
        initComponents();

        this.setupForm();
    }

    public Preferences(PreferenceChangeListener notify, int tab) {
        this.defaultPrefs(notify);
        initComponents();

        this.tabPrefs.setSelectedIndex(tab);

        this.setupForm();
    }

    public UnitProfile getProfile(int index) {
        return this.profiles[index];
    }

    private void setupForm() {
        boolean isTransparentable = AWTUtilitiesWrapper.isTranslucencySupported(AWTUtilitiesWrapper.TRANSLUCENT);
        
        if(!isTransparentable) {
            this.sldrTransparent.setEnabled(false);
            this.tbtnAlways.setEnabled(false);
            this.tbtnNever.setEnabled(false);
            this.tbtnOnFocus.setEnabled(false);
            this.lblTransparency.setEnabled(false);
        }

        this.sldrTransparent.setValue((int)(this.transparency * 100));

        this.frmTxtColor.setText(this.rulerColor);

        this.rdBtnVertical.setSelected(true);
        if(this.rulerMode.equals("horizontal"))
            this.rdBtnHorizontal.setSelected(true);

        this.sldrTransparent.setEnabled(true);
        if(this.transparencyMode.equals("never")) {
            this.sldrTransparent.setEnabled(false);
            this.tbtnNever.setSelected(true);
        } else if(this.transparencyMode.equals("focus")) {
            this.tbtnOnFocus.setSelected(true);
        } else {
            this.tbtnAlways.setSelected(true);
        }

        this.cbAlwaysOnTop.setSelected(this.aot);
        
        this.frmTxtColor.getDocument().addDocumentListener(this);

        // set up the Units tab
        this.cmbProfiles.removeAllItems();
        this.cmbRulerUnits.removeAllItems();
        for(int i=0, len=this.profiles.length; i<len; i++) {
            this.cmbProfiles.addItem(this.objize(this.profiles[i].getName()));
            this.cmbRulerUnits.addItem(this.objize(this.profiles[i].getName()));
        }
        this.cmbProfiles.setSelectedIndex(0);
        this.cmbRulerUnits.setSelectedIndex(this.rulerUnitType);
        
        this.loadProfile(this.profiles[0]);

        this.tckbrPreview.setBackground(Color.decode(this.rulerColor));
        this.btnSave.setEnabled(false);
    }

    private void loadProfile(UnitProfile p) {
        this.lblPPU.setText("Pixels per " + p.getName());
        this.jspnrPrecision.setValue( p.getPrecision() );
        this.jspnrResolution.setValue( p.getResolution() );

        if(p.getLabels()) {
            this.tbtnOn.setSelected(true);
        }
        else {
            this.tbtnOff.setSelected(true);
        }

        this.lstLevels.setModel(p.getLevels());
        this.updatePreview();
    }

    /**
     * A change to the current profile and needs to be reflected in the preview
     * window.
     * @param change Represents what was changed.
     */
    private void updatePreview() {
        UnitProfile p = this.getCurrentProfile();
        
        // update preview with current unit profile
        this.tckbrPreview.setLabels(p.getLabels());
        this.tckbrPreview.setPercision(p.getPrecision());
        this.tckbrPreview.setPolicy(p.getTickPolicy());

        // update gui
        this.tckbrPreview.repaint();
        this.tckbrPreview.validate();

    }

    /**
     * Marks the current profile as dirty
     */
    private void markProfileAsDirty() {
        int index = this.cmbProfiles.getSelectedIndex();
        
        if(-1 == index) return;

        this.dirtyProfiles[index] = true;
        this.btnSave.setEnabled(true);
    }

    private Object objize(final String item)  {
        return new Object() {
            @Override
            public String toString() { return item; }
        };
    }

    private void defaultPrefs(PreferenceChangeListener pcl){

        float pxPerInch = (float) Toolkit.getDefaultToolkit().getScreenResolution();
        int profileCnt, currentCnt, customCnt, i, len;

        // set up default profiles based on resolution for reseting profiles.
        this.px = new UnitProfile("Pixel", true, 0, 1f, "2:10:20");
        this.in = new UnitProfile("Inch", true, 2, pxPerInch,
                "float/tpu|1:float/tpu|2:float/tpu|4:float/tpu|8:float/tpu|16");
        this.cm = new UnitProfile("Centimeter", true, 0, pxPerInch / 2.54f,
                "float/tpu|1:float/tpu|10");
        this.pc = new UnitProfile("Pica", true, 0, pxPerInch / 6f, "float/tpu|1:float/tpu|3");

        this.prefs = java.util.prefs.Preferences.userNodeForPackage(Preferences.class);
        this.transparency = this.prefs.getFloat("transparency", Preferences.DEFAULT_TRANSPARENCY);
        this.transparencyMode = this.prefs.get("transparency-mode", Preferences.DEFAULT_TRANSPARENCY_MODE);
        this.rulerMode = this.prefs.get("ruler-mode", Preferences.DEFAULT_RULER_MODE);
        this.rulerColor = this.prefs.get("ruler-color", Preferences.DEFAULT_COLOR);
        this.rulerUnitType = this.prefs.getInt("ruler-unit-type", Preferences.DEFAULT_RULER_UNIT_TYPE);
        this.aot = this.prefs.getBoolean("always-on-top", Preferences.DEFAULT_ALWAYS_ON_TOP);

        profileCnt = this.prefs.getInt("profile.count", Preferences.DEFAULT_PROFILE_COUNT);
        this.profiles = new UnitProfile[profileCnt];

        // These profiles can be edited but not deleted
        this.profiles[0] = new UnitProfile(
            this.prefs.get("px.name", this.px.getName()),
            this.prefs.getBoolean("px.labels", this.px.getLabels()),
            this.prefs.getInt("px.precision", this.px.getPrecision()),
            this.prefs.getFloat("px.resolution", this.px.getResolution()),
            this.prefs.get("px.levels", this.px.getPolicy())
        );

        this.profiles[1] = new UnitProfile(
            this.prefs.get("in.name", this.in.getName()),
            this.prefs.getBoolean("in.labels", this.in.getLabels()),
            this.prefs.getInt("in.precision", this.in.getPrecision()),
            this.prefs.getFloat("in.resolution", this.in.getResolution()),
            this.prefs.get("in.levels", this.in.getPolicy())
        );

        this.profiles[2] = new UnitProfile(
            this.prefs.get("cm.name", this.cm.getName()),
            this.prefs.getBoolean("cm.labels", this.cm.getLabels()),
            this.prefs.getInt("cm.precision", this.cm.getPrecision()),
            this.prefs.getFloat("cm.resolution", this.cm.getResolution()),
            this.prefs.get("cm.levels", this.cm.getPolicy())
        );

        this.profiles[3] = new UnitProfile(
            this.prefs.get("pc.name", this.pc.getName()),
            this.prefs.getBoolean("pc.labels", this.pc.getLabels()),
            this.prefs.getInt("pc.precision", this.pc.getPrecision()),
            this.prefs.getFloat("pc.resolution", this.pc.getResolution()),
            this.prefs.get("pc.levels", this.pc.getPolicy())
        );
        
        // get custom profiles
        // these can be edited and deleted
        currentCnt = Preferences.DEFAULT_PROFILE_COUNT;
        customCnt = 1;
        while(profileCnt > currentCnt) {
            this.profiles[currentCnt] = new UnitProfile(
                this.prefs.get("cstm" + customCnt + ".name", this.px.getName()),
                this.prefs.getBoolean("cstm" + customCnt + ".labels", this.px.getLabels()),
                this.prefs.getInt("cstm" + customCnt + ".precision", this.px.getPrecision()),
                this.prefs.getFloat("cstm" + customCnt + ".resolution", this.px.getResolution()),
                this.prefs.get("cstm" + customCnt + ".levels", this.px.getPolicy())
            );
            customCnt++;
            currentCnt++;
        }

        // set up dirtyProfile array
        this.dirtyProfiles = new boolean[this.profiles.length];
        for(i=0,len=this.profiles.length; i<len; i++) {
            this.dirtyProfiles[i] = false;
        }

        this.prefs.addPreferenceChangeListener(pcl);
    }

    public void showTab(int tab) {
        this.tabPrefs.setSelectedIndex(tab);
    }

    public static String indextToProfileName(int index) {
        String saveName;

        switch(index) {
            case 0:
                saveName = "px";
                break;
            case 1:
                saveName = "in";
                break;
            case 2:
                saveName = "cm";
                break;
            case 3:
                saveName = "pc";
                break;
            default:
                saveName = "cstm" + Integer.toString(index - 3);
        }

        return saveName;
    }

    public static java.util.prefs.Preferences userPrefs() {
        //this.prefs = java.util.prefs.Preferences.userNodeForPackage(Preferences.class);
        return java.util.prefs.Preferences.userRoot().node("/com/leadiv/openrule");
    }

    /**
     * Helper function to cut down on code replication.
     * @return the current unit profile or the first profile if none is selected.
     */
    private UnitProfile getCurrentProfile() {
        int index = this.cmbProfiles.getSelectedIndex();

        if(-1 == index) return null;

        return this.profiles[index];
    }

    private void savePrefs() {
        // Units Tab -- need to make sure that all unit changes have been updated first.
        int i, len = this.dirtyProfiles.length;
        String saveName = "";

        for(i=0; i<len; i++) {
            if(this.dirtyProfiles[i]) {
                saveName = Preferences.indextToProfileName(i);
                this.prefs.put(saveName + ".name", this.profiles[i].getName());
                this.prefs.putBoolean(saveName + ".labels", this.profiles[i].getLabels());
                this.prefs.putInt(saveName + ".precision", this.profiles[i].getPrecision());
                this.prefs.putFloat(saveName + ".resolution", this.profiles[i].getResolution());
                this.prefs.put(saveName + ".levels", this.profiles[i].getPolicy());
            }
        }

        this.prefs.putInt("profile.count", this.profiles.length);

        try {
            this.prefs.flush();
        } catch (BackingStoreException ex) {
            Logger.getLogger(Preferences.class.getName()).log(Level.SEVERE, null, ex);
        }
        
        // General Tab
        this.transparency = this.sldrTransparent.getValue() / 100f;
        this.rulerColor = this.frmTxtColor.getText();

        this.rulerMode = "horizontal";
        if(this.rdBtnVertical.isSelected())
            this.rulerMode = "vertical";

        if(this.tbtnNever.isSelected()) {
            this.transparencyMode = "never";
        } else if(this.tbtnOnFocus.isSelected()) {
            this.transparencyMode = "focus";
        } else {
            this.transparencyMode = "always";
        }

        this.rulerUnitType = this.cmbRulerUnits.getSelectedIndex();

        // Always on Top
        this.aot = false;
        if(this.cbAlwaysOnTop.isSelected()) this.aot = true;
        this.prefs.putBoolean("always-on-top", this.aot);

        this.prefs.putFloat("transparency", this.transparency);
        this.prefs.putInt("ruler-unit-type", this.rulerUnitType);
        this.prefs.put("transparency-mode", this.transparencyMode);
        this.prefs.put("ruler-mode", this.rulerMode);
        this.prefs.put("ruler-color", this.rulerColor);

        // Flush prefs
        try {
            this.prefs.flush();
        } catch (BackingStoreException ex) {
            Logger.getLogger(Preferences.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        bgrpTransparency = new javax.swing.ButtonGroup();
        bgrpLayout = new javax.swing.ButtonGroup();
        bgrpLabels = new javax.swing.ButtonGroup();
        bgrpUnits = new javax.swing.ButtonGroup();
        bgrpDividers = new javax.swing.ButtonGroup();
        tabPrefs = new javax.swing.JTabbedPane();
        pnlGeneral = new javax.swing.JPanel();
        jScrollPane3 = new javax.swing.JScrollPane();
        pnlGeneralFlow = new javax.swing.JPanel();
        pnlGeneralForm = new javax.swing.JPanel();
        pnlOrientation = new javax.swing.JPanel();
        jLabel2 = new javax.swing.JLabel();
        rdBtnHorizontal = new javax.swing.JRadioButton();
        rdBtnVertical = new javax.swing.JRadioButton();
        pnlColor = new javax.swing.JPanel();
        jLabel3 = new javax.swing.JLabel();
        frmTxtColor = new javax.swing.JFormattedTextField();
        btnSetColor = new javax.swing.JButton();
        pnlTransparency = new javax.swing.JPanel();
        lblTransparency = new javax.swing.JLabel();
        sldrTransparent = new javax.swing.JSlider();
        pnlTransparencyControls = new javax.swing.JPanel();
        tbtnNever = new javax.swing.JToggleButton();
        tbtnOnFocus = new javax.swing.JToggleButton();
        tbtnAlways = new javax.swing.JToggleButton();
        pnlRulerUnits = new javax.swing.JPanel();
        jLabel6 = new javax.swing.JLabel();
        cmbRulerUnits = new javax.swing.JComboBox();
        pnlAlwaysOnTop = new javax.swing.JPanel();
        cbAlwaysOnTop = new javax.swing.JCheckBox();
        pnlUnits = new javax.swing.JPanel();
        jScrollPane2 = new javax.swing.JScrollPane();
        pnlUnitFlow = new javax.swing.JPanel();
        pnlUnitProfile = new javax.swing.JPanel();
        pnlMsg = new javax.swing.JPanel();
        msg = new javax.swing.JLabel();
        pnlPreview = new javax.swing.JPanel();
        tckbrPreview = new com.leadiv.openrule.TickBar();
        jSeparator1 = new javax.swing.JSeparator();
        pnlProfileControls = new javax.swing.JPanel();
        lblUnitProfile = new javax.swing.JLabel();
        cmbProfiles = new javax.swing.JComboBox();
        btnDelete = new javax.swing.JButton();
        btnNew = new javax.swing.JButton();
        pnlPrecision = new javax.swing.JPanel();
        jLabel4 = new javax.swing.JLabel();
        jspnrPrecision = new javax.swing.JSpinner();
        pnlLabels = new javax.swing.JPanel();
        jLabel5 = new javax.swing.JLabel();
        tbtnOn = new javax.swing.JToggleButton();
        tbtnOff = new javax.swing.JToggleButton();
        pnlResolution = new javax.swing.JPanel();
        jLabel1 = new javax.swing.JLabel();
        jspnrResolution = new javax.swing.JSpinner();
        lblPPU = new javax.swing.JLabel();
        pnlLevels = new javax.swing.JPanel();
        jPanel2 = new javax.swing.JPanel();
        jScrollPane1 = new javax.swing.JScrollPane();
        lstLevels = new javax.swing.JList();
        pnlLevelControls = new javax.swing.JPanel();
        cmbLevelType = new javax.swing.JComboBox();
        txtLevelValue = new javax.swing.JTextField();
        btnAddLevel = new javax.swing.JButton();
        btnRemoveLevel = new javax.swing.JButton();
        pnlAbout = new javax.swing.JPanel();
        jScrollPane4 = new javax.swing.JScrollPane();
        pnlAboutFlow = new javax.swing.JPanel();
        jPanel3 = new javax.swing.JPanel();
        pnlTxtLabels = new javax.swing.JPanel();
        lblProgramTitle = new javax.swing.JLabel();
        lblProgramVersion = new javax.swing.JLabel();
        jSeparator2 = new javax.swing.JSeparator();
        jPanel1 = new javax.swing.JPanel();
        jLabel7 = new javax.swing.JLabel();
        jPanel4 = new javax.swing.JPanel();
        lblcntrkey = new javax.swing.JLabel();
        jLabel10 = new javax.swing.JLabel();
        lblfmfmfm = new javax.swing.JLabel();
        pnlGlobalControls = new javax.swing.JPanel();
        btnSave = new javax.swing.JButton();
        btnClose = new javax.swing.JButton();

        setTitle("Preferences");
        setIconImage(new ImageIcon(this.getClass().getResource("/com/leadiv/openrule/gfx/cog.edit.png")).getImage());

        pnlGeneral.setLayout(new javax.swing.BoxLayout(pnlGeneral, javax.swing.BoxLayout.LINE_AXIS));

        pnlGeneralForm.setLayout(new javax.swing.BoxLayout(pnlGeneralForm, javax.swing.BoxLayout.PAGE_AXIS));

        pnlOrientation.setLayout(new java.awt.FlowLayout(java.awt.FlowLayout.LEFT));

        jLabel2.setText("Default Orientation: ");
        pnlOrientation.add(jLabel2);

        bgrpLayout.add(rdBtnHorizontal);
        rdBtnHorizontal.setText("Horizontal");
        rdBtnHorizontal.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                rdBtnHorizontalActionPerformed(evt);
            }
        });
        pnlOrientation.add(rdBtnHorizontal);

        bgrpLayout.add(rdBtnVertical);
        rdBtnVertical.setText("Vertical");
        rdBtnVertical.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                rdBtnVerticalActionPerformed(evt);
            }
        });
        pnlOrientation.add(rdBtnVertical);

        pnlGeneralForm.add(pnlOrientation);

        pnlColor.setLayout(new java.awt.FlowLayout(java.awt.FlowLayout.LEFT));

        jLabel3.setText("Color:");
        pnlColor.add(jLabel3);

        frmTxtColor.setColumns(7);
        try {
            frmTxtColor.setFormatterFactory(new javax.swing.text.DefaultFormatterFactory(new javax.swing.text.MaskFormatter("'#HHHHHH")));
        } catch (java.text.ParseException ex) {
            ex.printStackTrace();
        }
        frmTxtColor.setText("#ffffff");
        pnlColor.add(frmTxtColor);

        btnSetColor.setText("Set Color...");
        btnSetColor.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btnSetColorActionPerformed(evt);
            }
        });
        pnlColor.add(btnSetColor);

        pnlGeneralForm.add(pnlColor);

        lblTransparency.setText("Transparency:");
        pnlTransparency.add(lblTransparency);

        sldrTransparent.setMinimum(1);
        sldrTransparent.addChangeListener(new javax.swing.event.ChangeListener() {
            public void stateChanged(javax.swing.event.ChangeEvent evt) {
                sldrTransparentStateChanged(evt);
            }
        });
        pnlTransparency.add(sldrTransparent);

        pnlGeneralForm.add(pnlTransparency);

        bgrpTransparency.add(tbtnNever);
        tbtnNever.setText("Never");
        tbtnNever.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                tbtnNeverActionPerformed(evt);
            }
        });
        pnlTransparencyControls.add(tbtnNever);

        bgrpTransparency.add(tbtnOnFocus);
        tbtnOnFocus.setText("On Focus Lost");
        tbtnOnFocus.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                tbtnOnFocusActionPerformed(evt);
            }
        });
        pnlTransparencyControls.add(tbtnOnFocus);

        bgrpTransparency.add(tbtnAlways);
        tbtnAlways.setText("Always");
        tbtnAlways.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                tbtnAlwaysActionPerformed(evt);
            }
        });
        pnlTransparencyControls.add(tbtnAlways);

        pnlGeneralForm.add(pnlTransparencyControls);

        pnlRulerUnits.setLayout(new java.awt.FlowLayout(java.awt.FlowLayout.LEFT));

        jLabel6.setText("Unit Type:");
        pnlRulerUnits.add(jLabel6);

        cmbRulerUnits.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "Item 1", "Item 2", "Item 3", "Item 4" }));
        cmbRulerUnits.addItemListener(new java.awt.event.ItemListener() {
            public void itemStateChanged(java.awt.event.ItemEvent evt) {
                cmbRulerUnitsItemStateChanged(evt);
            }
        });
        pnlRulerUnits.add(cmbRulerUnits);

        pnlGeneralForm.add(pnlRulerUnits);

        pnlAlwaysOnTop.setLayout(new java.awt.FlowLayout(java.awt.FlowLayout.LEFT));

        cbAlwaysOnTop.setText("Always on Top");
        cbAlwaysOnTop.addChangeListener(new javax.swing.event.ChangeListener() {
            public void stateChanged(javax.swing.event.ChangeEvent evt) {
                cbAlwaysOnTopStateChanged(evt);
            }
        });
        pnlAlwaysOnTop.add(cbAlwaysOnTop);

        pnlGeneralForm.add(pnlAlwaysOnTop);

        pnlGeneralFlow.add(pnlGeneralForm);

        jScrollPane3.setViewportView(pnlGeneralFlow);

        pnlGeneral.add(jScrollPane3);

        tabPrefs.addTab("General", pnlGeneral);

        pnlUnits.setLayout(new javax.swing.BoxLayout(pnlUnits, javax.swing.BoxLayout.PAGE_AXIS));

        pnlUnitProfile.setLayout(new javax.swing.BoxLayout(pnlUnitProfile, javax.swing.BoxLayout.PAGE_AXIS));

        pnlMsg.setLayout(new java.awt.FlowLayout(java.awt.FlowLayout.LEFT, 5, 0));

        msg.setForeground(new java.awt.Color(202, 0, 0));
        pnlMsg.add(msg);

        pnlUnitProfile.add(pnlMsg);

        pnlPreview.setBorder(javax.swing.BorderFactory.createEmptyBorder(10, 10, 10, 10));
        pnlPreview.setLayout(new javax.swing.BoxLayout(pnlPreview, javax.swing.BoxLayout.LINE_AXIS));

        tckbrPreview.setPreferredSize(new java.awt.Dimension(0, 40));
        pnlPreview.add(tckbrPreview);

        pnlUnitProfile.add(pnlPreview);
        pnlUnitProfile.add(jSeparator1);

        pnlProfileControls.setLayout(new java.awt.FlowLayout(java.awt.FlowLayout.LEFT));

        lblUnitProfile.setText("Unit Profiles: ");
        pnlProfileControls.add(lblUnitProfile);

        cmbProfiles.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "Item 1", "Item 2", "Item 3", "Item 4" }));
        cmbProfiles.addItemListener(new java.awt.event.ItemListener() {
            public void itemStateChanged(java.awt.event.ItemEvent evt) {
                cmbProfilesItemStateChanged(evt);
            }
        });
        pnlProfileControls.add(cmbProfiles);

        btnDelete.setText("Delete");
        btnDelete.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btnDeleteActionPerformed(evt);
            }
        });
        pnlProfileControls.add(btnDelete);

        btnNew.setText("New...");
        btnNew.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btnNewActionPerformed(evt);
            }
        });
        pnlProfileControls.add(btnNew);

        pnlUnitProfile.add(pnlProfileControls);

        pnlPrecision.setBorder(javax.swing.BorderFactory.createEmptyBorder(1, 5, 1, 5));
        pnlPrecision.setLayout(new javax.swing.BoxLayout(pnlPrecision, javax.swing.BoxLayout.LINE_AXIS));

        jLabel4.setText("Ruler Precision:");
        jLabel4.setBorder(javax.swing.BorderFactory.createEmptyBorder(1, 1, 1, 5));
        pnlPrecision.add(jLabel4);

        jspnrPrecision.setModel(new javax.swing.SpinnerNumberModel(Integer.valueOf(1), Integer.valueOf(0), null, Integer.valueOf(1)));
        jspnrPrecision.addChangeListener(new javax.swing.event.ChangeListener() {
            public void stateChanged(javax.swing.event.ChangeEvent evt) {
                jspnrPrecisionStateChanged(evt);
            }
        });
        pnlPrecision.add(jspnrPrecision);

        pnlUnitProfile.add(pnlPrecision);

        pnlLabels.setLayout(new java.awt.FlowLayout(java.awt.FlowLayout.LEFT));

        jLabel5.setText("Unit Labels:");
        pnlLabels.add(jLabel5);

        bgrpLabels.add(tbtnOn);
        tbtnOn.setText("On");
        tbtnOn.addChangeListener(new javax.swing.event.ChangeListener() {
            public void stateChanged(javax.swing.event.ChangeEvent evt) {
                tbtnOnStateChanged(evt);
            }
        });
        pnlLabels.add(tbtnOn);

        bgrpLabels.add(tbtnOff);
        tbtnOff.setText("Off");
        tbtnOff.addChangeListener(new javax.swing.event.ChangeListener() {
            public void stateChanged(javax.swing.event.ChangeEvent evt) {
                tbtnOffStateChanged(evt);
            }
        });
        pnlLabels.add(tbtnOff);

        pnlUnitProfile.add(pnlLabels);

        pnlResolution.setBorder(javax.swing.BorderFactory.createEmptyBorder(1, 5, 1, 5));
        pnlResolution.setLayout(new javax.swing.BoxLayout(pnlResolution, javax.swing.BoxLayout.LINE_AXIS));

        jLabel1.setText("Unit Resolution:");
        jLabel1.setBorder(javax.swing.BorderFactory.createEmptyBorder(1, 1, 1, 5));
        pnlResolution.add(jLabel1);

        jspnrResolution.setModel(new javax.swing.SpinnerNumberModel(Float.valueOf(1.0f), Float.valueOf(1.0f), null, Float.valueOf(1.0f)));
        jspnrResolution.addChangeListener(new javax.swing.event.ChangeListener() {
            public void stateChanged(javax.swing.event.ChangeEvent evt) {
                jspnrResolutionStateChanged(evt);
            }
        });
        pnlResolution.add(jspnrResolution);

        lblPPU.setText("Pixels Per <unit>");
        lblPPU.setBorder(javax.swing.BorderFactory.createEmptyBorder(1, 5, 1, 1));
        pnlResolution.add(lblPPU);

        pnlUnitProfile.add(pnlResolution);

        pnlLevels.setBorder(javax.swing.BorderFactory.createTitledBorder(javax.swing.BorderFactory.createCompoundBorder(null, javax.swing.BorderFactory.createEtchedBorder()), "Pixel Levels", javax.swing.border.TitledBorder.DEFAULT_JUSTIFICATION, javax.swing.border.TitledBorder.TOP));
        pnlLevels.setLayout(new javax.swing.BoxLayout(pnlLevels, javax.swing.BoxLayout.PAGE_AXIS));

        jPanel2.setBorder(javax.swing.BorderFactory.createEmptyBorder(1, 10, 1, 10));
        jPanel2.setLayout(new javax.swing.BoxLayout(jPanel2, javax.swing.BoxLayout.PAGE_AXIS));

        lstLevels.setModel(new javax.swing.AbstractListModel() {
            String[] strings = { "Item 1", "Item 2", "Item 3", "Item 4", "Item 5" };
            public int getSize() { return strings.length; }
            public Object getElementAt(int i) { return strings[i]; }
        });
        jScrollPane1.setViewportView(lstLevels);

        jPanel2.add(jScrollPane1);

        pnlLevelControls.setBorder(javax.swing.BorderFactory.createEmptyBorder(5, 1, 1, 1));
        pnlLevelControls.setLayout(new java.awt.GridLayout(0, 2, 2, 2));

        cmbLevelType.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "Pixel Per Tick", "Ticks Per Unit" }));
        pnlLevelControls.add(cmbLevelType);
        pnlLevelControls.add(txtLevelValue);

        btnAddLevel.setText("Add");
        btnAddLevel.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btnAddLevelActionPerformed(evt);
            }
        });
        pnlLevelControls.add(btnAddLevel);

        btnRemoveLevel.setText("Remove");
        btnRemoveLevel.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btnRemoveLevelActionPerformed(evt);
            }
        });
        pnlLevelControls.add(btnRemoveLevel);

        jPanel2.add(pnlLevelControls);

        pnlLevels.add(jPanel2);

        pnlUnitProfile.add(pnlLevels);

        pnlUnitFlow.add(pnlUnitProfile);

        jScrollPane2.setViewportView(pnlUnitFlow);

        pnlUnits.add(jScrollPane2);

        tabPrefs.addTab("Units", pnlUnits);

        pnlAbout.setPreferredSize(new java.awt.Dimension(300, 100));
        pnlAbout.setLayout(new javax.swing.BoxLayout(pnlAbout, javax.swing.BoxLayout.LINE_AXIS));

        jPanel3.setLayout(new javax.swing.BoxLayout(jPanel3, javax.swing.BoxLayout.PAGE_AXIS));

        pnlTxtLabels.setBorder(javax.swing.BorderFactory.createEmptyBorder(1, 1, 10, 1));

        lblProgramTitle.setFont(new java.awt.Font("Tahoma", 0, 14)); // NOI18N
        lblProgramTitle.setText("OpenRule");
        pnlTxtLabels.add(lblProgramTitle);

        lblProgramVersion.setFont(new java.awt.Font("Tahoma", 0, 14)); // NOI18N
        lblProgramVersion.setText(" Version 2.0.320 (Venus)");
        pnlTxtLabels.add(lblProgramVersion);

        jPanel3.add(pnlTxtLabels);
        jPanel3.add(jSeparator2);

        jPanel1.setBorder(javax.swing.BorderFactory.createEmptyBorder(10, 1, 1, 1));

        jLabel7.setFont(new java.awt.Font("Tahoma", 1, 14)); // NOI18N
        jLabel7.setText("Special Thanks");
        jPanel1.add(jLabel7);

        jPanel3.add(jPanel1);

        lblcntrkey.setFont(new java.awt.Font("Tahoma", 1, 11)); // NOI18N
        lblcntrkey.setForeground(new java.awt.Color(0, 51, 255));
        lblcntrkey.setText("centerkey.com");
        lblcntrkey.setCursor(new java.awt.Cursor(java.awt.Cursor.HAND_CURSOR));
        lblcntrkey.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                lblcntrkeyMouseClicked(evt);
            }
        });
        jPanel4.add(lblcntrkey);

        jLabel10.setText("and");
        jPanel4.add(jLabel10);

        lblfmfmfm.setFont(new java.awt.Font("Tahoma", 1, 11)); // NOI18N
        lblfmfmfm.setForeground(new java.awt.Color(0, 51, 255));
        lblfmfmfm.setText("famfamfam.com");
        lblfmfmfm.setCursor(new java.awt.Cursor(java.awt.Cursor.HAND_CURSOR));
        lblfmfmfm.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                lblfmfmfmMouseClicked(evt);
            }
        });
        jPanel4.add(lblfmfmfm);

        jPanel3.add(jPanel4);

        pnlAboutFlow.add(jPanel3);

        jScrollPane4.setViewportView(pnlAboutFlow);

        pnlAbout.add(jScrollPane4);

        tabPrefs.addTab("About", pnlAbout);

        getContentPane().add(tabPrefs, java.awt.BorderLayout.CENTER);

        pnlGlobalControls.setLayout(new java.awt.FlowLayout(java.awt.FlowLayout.RIGHT));

        btnSave.setText("Save");
        btnSave.setEnabled(false);
        btnSave.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btnSaveActionPerformed(evt);
            }
        });
        pnlGlobalControls.add(btnSave);

        btnClose.setText("Close");
        btnClose.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btnCloseActionPerformed(evt);
            }
        });
        pnlGlobalControls.add(btnClose);

        getContentPane().add(pnlGlobalControls, java.awt.BorderLayout.SOUTH);

        pack();
    }// </editor-fold>//GEN-END:initComponents

private void btnCloseActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnCloseActionPerformed
    // close without saving changes...
    this.dispose();
}//GEN-LAST:event_btnCloseActionPerformed

private void sldrTransparentStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_sldrTransparentStateChanged
    this.btnSave.setEnabled(true);
}//GEN-LAST:event_sldrTransparentStateChanged

private void btnSaveActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnSaveActionPerformed
    this.savePrefs();
    this.btnSave.setEnabled(false);
}//GEN-LAST:event_btnSaveActionPerformed

private void tbtnNeverActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_tbtnNeverActionPerformed
    this.sldrTransparent.setEnabled(false);
    this.btnSave.setEnabled(true);
}//GEN-LAST:event_tbtnNeverActionPerformed

private void rdBtnHorizontalActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_rdBtnHorizontalActionPerformed
    this.btnSave.setEnabled(true);
}//GEN-LAST:event_rdBtnHorizontalActionPerformed

private void rdBtnVerticalActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_rdBtnVerticalActionPerformed
    this.btnSave.setEnabled(true);
}//GEN-LAST:event_rdBtnVerticalActionPerformed

private void tbtnOnFocusActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_tbtnOnFocusActionPerformed
    this.sldrTransparent.setEnabled(true);
    this.btnSave.setEnabled(true);
}//GEN-LAST:event_tbtnOnFocusActionPerformed

private void tbtnAlwaysActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_tbtnAlwaysActionPerformed
    this.sldrTransparent.setEnabled(true);
    this.btnSave.setEnabled(true);
}//GEN-LAST:event_tbtnAlwaysActionPerformed

private void btnSetColorActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnSetColorActionPerformed
    Color newColor = JColorChooser.showDialog(this,"Choose Ruler Color", Utilities.hstoc(this.rulerColor));

    if(newColor != null) {
        this.rulerColor = Utilities.ctohs(newColor);
        this.frmTxtColor.setText(this.rulerColor);
    }
}//GEN-LAST:event_btnSetColorActionPerformed

private void cmbProfilesItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_cmbProfilesItemStateChanged
    int i = this.cmbProfiles.getSelectedIndex();
    boolean saveState = this.btnSave.isEnabled();

    if(-1 != i) {
        this.loadProfile(this.profiles[i]);

        this.btnDelete.setText("Delete");
        if(Preferences.DEFAULT_PROFILE_COUNT > i) {
            this.btnDelete.setText("Reset");
        }
        
        this.btnSave.setEnabled(saveState);
    }
}//GEN-LAST:event_cmbProfilesItemStateChanged

private void cbAlwaysOnTopStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_cbAlwaysOnTopStateChanged
    this.btnSave.setEnabled(true);
}//GEN-LAST:event_cbAlwaysOnTopStateChanged

private void btnDeleteActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnDeleteActionPerformed
    if(this.btnDelete.getText().equals("Delete")) {
        int cur = this.cmbProfiles.getSelectedIndex();
        UnitProfile tmp[] = new UnitProfile[this.profiles.length - 1];
        boolean tmp2[] = new boolean[this.dirtyProfiles.length - 1];

        DefaultComboBoxModel lm = (DefaultComboBoxModel) this.cmbProfiles.getModel();
        DefaultComboBoxModel lm2 = (DefaultComboBoxModel) this.cmbRulerUnits.getModel();

        lm.removeElementAt(cur);
        lm2.removeElementAt(cur);
        for(int i=this.cmbProfiles.getSelectedIndex(), len=this.profiles.length-1; i<len; i++) {
            this.profiles[i] = this.profiles[i+1];
        }

        System.arraycopy(this.profiles, 0, tmp, 0, this.profiles.length - 1);
        this.profiles = new UnitProfile[this.profiles.length - 1];
        System.arraycopy(tmp, 0, this.profiles, 0, tmp.length);

        System.arraycopy(this.dirtyProfiles, 0, tmp2, 0, this.dirtyProfiles.length - 1);
        this.dirtyProfiles = new boolean[this.dirtyProfiles.length - 1];
        System.arraycopy(tmp2, 0, this.dirtyProfiles, 0, tmp2.length);

        if(cur == this.profiles.length) cur--;
        this.loadProfile(this.profiles[cur]);
        this.cmbProfiles.setModel(lm);
        this.cmbRulerUnits.setModel(lm2);
    }

    if(this.btnDelete.getText().equals("Reset")) {
       DefaultComboBoxModel lm = (DefaultComboBoxModel) this.cmbProfiles.getModel();

       String selectedProfile = lm.getSelectedItem().toString();

       if(selectedProfile.equals(this.px.getName())) {
            this.profiles[0] = new UnitProfile(
                this.px.getName(),
                this.px.getLabels(),
                this.px.getPrecision(),
                this.px.getResolution(),
                this.px.getPolicy()
            );

           this.loadProfile(this.profiles[0]);
       }

       if(selectedProfile.equals(this.in.getName())) {
            this.profiles[1] = new UnitProfile(
                this.in.getName(),
                this.in.getLabels(),
                this.in.getPrecision(),
                this.in.getResolution(),
                this.in.getPolicy()
            );
            this.loadProfile(this.profiles[1]);
       }

       if(selectedProfile.equals(this.cm.getName())) {
            this.profiles[2] = new UnitProfile(
                this.cm.getName(),
                this.cm.getLabels(),
                this.cm.getPrecision(),
                this.cm.getResolution(),
                this.cm.getPolicy()
            );
            this.loadProfile(this.profiles[2]);
       }

       if(selectedProfile.equals(this.pc.getName())) {
            this.profiles[3] = new UnitProfile(
                 this.pc.getName(),
                this.pc.getLabels(),
                this.pc.getPrecision(),
                this.pc.getResolution(),
                this.pc.getPolicy()
            );
            this.loadProfile(this.profiles[3]);
       }
    }

    this.btnSave.setEnabled(true);
}//GEN-LAST:event_btnDeleteActionPerformed

private void btnNewActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnNewActionPerformed
    boolean created = false;
    UnitProfile tmp[] = new UnitProfile[this.profiles.length];
    boolean tmp2[] = new boolean[this.dirtyProfiles.length];
    int last = 0;
    int rulerUnitsSelected = this.cmbRulerUnits.getSelectedIndex();

    userInput: do {
        String s = (String)JOptionPane.showInputDialog(
                        this,
                        "Profile Name:",
                        "New Profile",
                        JOptionPane.PLAIN_MESSAGE,
                        null,
                        null,
                        "");

        if(null == s) return;

        for(int i=0, len = this.profiles.length; i<len; i++) {
            if(s.equals(this.profiles[i].getName())) {
                JOptionPane.showMessageDialog(
                        this,
                        "Profile name already in use. Please choose a different name",
                        "Profile Creation Error",
                        JOptionPane.ERROR_MESSAGE
                        );
                continue userInput;
            }
        }


        // Extend the profiles array by 1.
        System.arraycopy(this.profiles, 0, tmp, 0, this.profiles.length);
        this.profiles = new UnitProfile[tmp.length+1];
        System.arraycopy(tmp, 0, this.profiles, 0, tmp.length);

        // Extend the dirtyProfiles array by 1
        System.arraycopy(this.dirtyProfiles, 0, tmp2, 0, this.dirtyProfiles.length);
        this.dirtyProfiles = new boolean[tmp2.length+1];
        System.arraycopy(tmp2, 0, this.dirtyProfiles, 0, tmp2.length);
        this.dirtyProfiles[this.dirtyProfiles.length - 1] = true;
        
        last = this.profiles.length-1;
        this.profiles[last] = new UnitProfile();
        this.profiles[last].setName(s);
        this.profiles[last].setResolution(1f); // set default resolution

        // Add profile to profile dropdown
        DefaultComboBoxModel lm = (DefaultComboBoxModel)this.cmbProfiles.getModel();
        DefaultComboBoxModel lm2 = (DefaultComboBoxModel)this.cmbRulerUnits.getModel();
        lm.addElement(s);
        lm2.addElement(s);
        this.cmbProfiles.setModel(lm);
        this.cmbRulerUnits.setModel(lm2);
        this.cmbProfiles.setSelectedIndex(this.profiles.length - 1);

        created = true;
    } while(!created);

    this.btnSave.setEnabled(true);
}//GEN-LAST:event_btnNewActionPerformed

private void btnAddLevelActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnAddLevelActionPerformed
    float f;
    String needle;
    UnitProfile p;
    String type = this.cmbLevelType.getSelectedItem().toString();

    p = this.getCurrentProfile();

    try {
        f = Float.parseFloat(this.txtLevelValue.getText().trim());

        if(f == (int)f) {
            needle = Integer.toString((int)f) + " " + type;
        } else {
            needle = Float.toString(f) + " " + type;
        }

        if(!p.isLevel(needle)) {
            p.addLevel(needle);
            this.lstLevels.setModel(p.getLevels());
            this.txtLevelValue.setText("");
            this.updatePreview();
            this.markProfileAsDirty();
        }
   } catch(java.lang.NumberFormatException nfe) {
        // do nothing
    }
}//GEN-LAST:event_btnAddLevelActionPerformed

private void btnRemoveLevelActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnRemoveLevelActionPerformed
    UnitProfile p;
    int index = this.lstLevels.getSelectedIndex();

    p = this.getCurrentProfile();

    if(-1 != index) {
        p.removeLevel(index);
        this.lstLevels.setModel(p.getLevels());
        this.updatePreview();
        this.markProfileAsDirty();
    }
}//GEN-LAST:event_btnRemoveLevelActionPerformed

private void tbtnOnStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_tbtnOnStateChanged
    UnitProfile p = this.getCurrentProfile();
    if(this.tbtnOn.isSelected()) {
        p.setLabels(true);
        this.updatePreview();
        this.markProfileAsDirty();
    }
}//GEN-LAST:event_tbtnOnStateChanged

private void tbtnOffStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_tbtnOffStateChanged
    UnitProfile p = this.getCurrentProfile();

    if(this.tbtnOff.isSelected()) {
        p.setLabels(false);
        this.updatePreview();
        this.markProfileAsDirty();
    }
}//GEN-LAST:event_tbtnOffStateChanged

private void jspnrPrecisionStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_jspnrPrecisionStateChanged
    int val;
    UnitProfile p = this.getCurrentProfile();

    try {
        val = Integer.parseInt(this.jspnrPrecision.getValue().toString().trim());

        p.setPrecision(val);
        this.updatePreview();
        this.markProfileAsDirty();
    } catch(java.lang.NumberFormatException nfe) {
        // do nothing
    }
}//GEN-LAST:event_jspnrPrecisionStateChanged

private void jspnrResolutionStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_jspnrResolutionStateChanged
    UnitProfile p = this.getCurrentProfile();

    try {
        p.setResolution(Float.parseFloat(this.jspnrResolution.getValue().toString().trim()));
        this.updatePreview();
        this.markProfileAsDirty();
    } catch (java.lang.NumberFormatException nfe) {
        // noop
    }
}//GEN-LAST:event_jspnrResolutionStateChanged

private void cmbRulerUnitsItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_cmbRulerUnitsItemStateChanged
    this.btnSave.setEnabled(true);
}//GEN-LAST:event_cmbRulerUnitsItemStateChanged

private void lblcntrkeyMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_lblcntrkeyMouseClicked
    BareBonesBrowserLaunch.openURL("http://www.centerkey.com/java/browser");
}//GEN-LAST:event_lblcntrkeyMouseClicked

private void lblfmfmfmMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_lblfmfmfmMouseClicked
    BareBonesBrowserLaunch.openURL("http://famfamfam.com/lab/icons/silk");
}//GEN-LAST:event_lblfmfmfmMouseClicked


//@Override
public void insertUpdate(DocumentEvent e) {
    String s = this.frmTxtColor.getText();

    this.btnSave.setEnabled(true);
    if(s.contains(" ") || s.equals(this.rulerColor))
        this.btnSave.setEnabled(false);
}

//@Override
public void removeUpdate(DocumentEvent e) {
    String s = this.frmTxtColor.getText();

    this.btnSave.setEnabled(true);
    if(s.contains(" ") || s.equals(this.rulerColor))
        this.btnSave.setEnabled(false);
}

//@Override
public void changedUpdate(DocumentEvent e) {
    // We dont need this one...
}

    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.ButtonGroup bgrpDividers;
    private javax.swing.ButtonGroup bgrpLabels;
    private javax.swing.ButtonGroup bgrpLayout;
    private javax.swing.ButtonGroup bgrpTransparency;
    private javax.swing.ButtonGroup bgrpUnits;
    private javax.swing.JButton btnAddLevel;
    private javax.swing.JButton btnClose;
    private javax.swing.JButton btnDelete;
    private javax.swing.JButton btnNew;
    private javax.swing.JButton btnRemoveLevel;
    private javax.swing.JButton btnSave;
    private javax.swing.JButton btnSetColor;
    private javax.swing.JCheckBox cbAlwaysOnTop;
    private javax.swing.JComboBox cmbLevelType;
    private javax.swing.JComboBox cmbProfiles;
    private javax.swing.JComboBox cmbRulerUnits;
    private javax.swing.JFormattedTextField frmTxtColor;
    private javax.swing.JLabel jLabel1;
    private javax.swing.JLabel jLabel10;
    private javax.swing.JLabel jLabel2;
    private javax.swing.JLabel jLabel3;
    private javax.swing.JLabel jLabel4;
    private javax.swing.JLabel jLabel5;
    private javax.swing.JLabel jLabel6;
    private javax.swing.JLabel jLabel7;
    private javax.swing.JPanel jPanel1;
    private javax.swing.JPanel jPanel2;
    private javax.swing.JPanel jPanel3;
    private javax.swing.JPanel jPanel4;
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JScrollPane jScrollPane2;
    private javax.swing.JScrollPane jScrollPane3;
    private javax.swing.JScrollPane jScrollPane4;
    private javax.swing.JSeparator jSeparator1;
    private javax.swing.JSeparator jSeparator2;
    private javax.swing.JSpinner jspnrPrecision;
    private javax.swing.JSpinner jspnrResolution;
    private javax.swing.JLabel lblPPU;
    private javax.swing.JLabel lblProgramTitle;
    private javax.swing.JLabel lblProgramVersion;
    private javax.swing.JLabel lblTransparency;
    private javax.swing.JLabel lblUnitProfile;
    private javax.swing.JLabel lblcntrkey;
    private javax.swing.JLabel lblfmfmfm;
    private javax.swing.JList lstLevels;
    private javax.swing.JLabel msg;
    private javax.swing.JPanel pnlAbout;
    private javax.swing.JPanel pnlAboutFlow;
    private javax.swing.JPanel pnlAlwaysOnTop;
    private javax.swing.JPanel pnlColor;
    private javax.swing.JPanel pnlGeneral;
    private javax.swing.JPanel pnlGeneralFlow;
    private javax.swing.JPanel pnlGeneralForm;
    private javax.swing.JPanel pnlGlobalControls;
    private javax.swing.JPanel pnlLabels;
    private javax.swing.JPanel pnlLevelControls;
    private javax.swing.JPanel pnlLevels;
    private javax.swing.JPanel pnlMsg;
    private javax.swing.JPanel pnlOrientation;
    private javax.swing.JPanel pnlPrecision;
    private javax.swing.JPanel pnlPreview;
    private javax.swing.JPanel pnlProfileControls;
    private javax.swing.JPanel pnlResolution;
    private javax.swing.JPanel pnlRulerUnits;
    private javax.swing.JPanel pnlTransparency;
    private javax.swing.JPanel pnlTransparencyControls;
    private javax.swing.JPanel pnlTxtLabels;
    private javax.swing.JPanel pnlUnitFlow;
    private javax.swing.JPanel pnlUnitProfile;
    private javax.swing.JPanel pnlUnits;
    private javax.swing.JRadioButton rdBtnHorizontal;
    private javax.swing.JRadioButton rdBtnVertical;
    private javax.swing.JSlider sldrTransparent;
    private javax.swing.JTabbedPane tabPrefs;
    private javax.swing.JToggleButton tbtnAlways;
    private javax.swing.JToggleButton tbtnNever;
    private javax.swing.JToggleButton tbtnOff;
    private javax.swing.JToggleButton tbtnOn;
    private javax.swing.JToggleButton tbtnOnFocus;
    private com.leadiv.openrule.TickBar tckbrPreview;
    private javax.swing.JTextField txtLevelValue;
    // End of variables declaration//GEN-END:variables

    static final int GENERAL_TAB = 0;
    static final int UNITS_TAB = 1;
    static final int ABOUT_TAB = 2;

    static final float DEFAULT_TRANSPARENCY = 1f;
    static final String DEFAULT_TRANSPARENCY_MODE = "never";
    static final String DEFAULT_RULER_MODE = "horizontal";
    static final String DEFAULT_COLOR = "#fce94f";
    static final int DEFAULT_PROFILE_COUNT = 4;
    static final boolean DEFAULT_ALWAYS_ON_TOP = true;
    static final int DEFAULT_RULER_UNIT_TYPE = 0;

    private java.util.prefs.Preferences prefs;
    private boolean aot;
    private float transparency;
    private int rulerUnitType;
    private String transparencyMode;
    private String rulerMode;
    private String rulerColor;
    private boolean[] dirtyProfiles;
    private UnitProfile[] profiles;
    private UnitProfile px, in, cm, pc;
    Hashtable<String, Integer> divisionLookup = new Hashtable<String, Integer>();
}
